import {extend} from 'quasar';

let dev = false;

export const defaultValue = () => {
  return {
    name: '',
    round: 1,
    boss: 1,
    damage: [0, 0],
    characters: [0, 0, 0, 0, 0],
    filter: {},
    actions: [],
    description: '',
    disable: false
  }
};

export function calcTeam(teams, box, count) {
  const copyObject = (object) => {
    try {
      return JSON.parse(JSON.stringify(object));
    } catch {
      return object;
    }
  }

  if (!count) count = 3;
  const isInBox = (box_, id, filter) => {
    const isEquipmentSame = (list1, list2) => {
      if (!list1 || !list2) return false;
      const a = (typeof list1 === 'array') ? list1 : Object.values(list1);
      const b = (typeof list2 === 'array') ? list2 : Object.values(list2);
      return a.toString() === b.toString();
    }
    for (const character in box_) {
      if (box_[character].id === id) {
        if (box_[character].disable) return false;
        if (!filter) return true;
        const max = (array) => {
          let max;
          for (const i of array) {
            if (typeof max !== 'number' || i > max) max = i;
          }
          return max;
        }
        const min = (array) => {
          let min;
          for (const i of array) {
            if (typeof min !== 'number' || i < min) min = i;
          }
          return min;
        }
        if (filter.rank && (box_[character].rank < min(filter.rank) || box_[character].rank > max(filter.rank))) {
          devLog(`Rank不符！角色Rank：${box_[character].rank}，要求Rank：${min(filter.rank)}-${max(filter.rank)}`);
          return false;
        }
        if (filter.star && (box_[character].star < min(filter.star) || box_[character].star > max(filter.star))) {
          devLog(`星级不符！角色星级：${box_[character].star}，要求星级：${min(filter.star)}-${max(filter.star)}`);
          return false;
        }
        if (
          filter.equipment &&
          filter.rank &&
          min(filter.rank) === max(filter.rank) &&
          !isEquipmentSame(box_[character].equipment, filter.equipment)) {
          devLog(`装备不符！角色装备：${Object.values(box_[character].equipment).toString()}，要求装备：${filter.equipment.toString()}`);
          return false;
        }
        if (filter.weapon && (box_[character].weapon < min(filter.weapon) || box_[character].weapon > max(filter.weapon))) {
          devLog(`专武不符！角色专武：${box_[character].weapon}，要求专武：${min(filter.weapon)}-${max(filter.weapon)}`);
          return false;
        }
        return true;
      }
    }
    return false;
  }
  let availableTeams = [];
  teams.forEach(team => {
    devLog('检查队伍可用性', team);
    let borrowCharacterID = null;
    for (const character of team.characters) {
      devLog(character, team.filter[character]);
      if (!isInBox(box, character, team.filter[character])) {
        if (borrowCharacterID) {
          devLog('已借用，退出。')
          return;
        }
        else {
          devLog(`借用${character}。`);
          borrowCharacterID = character;
        }
      }
    }
    let availableTeam = copyObject(team);
    availableTeam.borrow = borrowCharacterID;
    availableTeams.push(availableTeam);
  });
  devLog(availableTeams);
  if (availableTeams.length < count) return [];
  /* 获取所有可能的组合 */
  let teamGroups = [];
  let teamIdGroup = [];
  const getTeamGroups = (start) => {
    for (let i = start; i < availableTeams.length; i++) {
      if (teamIdGroup.indexOf(i) > -1) continue;
      teamIdGroup.push(i);
      if (teamIdGroup.length < count) getTeamGroups(i + 1);
      else {
        let teamGroup = [];
        teamIdGroup.forEach(teamId => {
          teamGroup.push(copyObject(availableTeams[teamId]));
        })
        teamGroups.push(teamGroup);
      }
      teamIdGroup.pop();
    }
  }
  getTeamGroups(0);
  /* 逐个判断队伍组成是否合理 */
  /*
    算法：
    遇到一个角色时，检查box内是否含有该角色。
    a. 如果有，将这个角色放到队伍中，并继续检查；
       然后将角色放回box，检查借人位：
       1. 若空闲，则放入，并继续检查；
       2. 若非空闲，无法组成，回上一步。
       然后将角色放回；
    b. 如果没有，则判断对应队伍的借人位是否空闲：
       1. 若空闲或是必借角色，则放入，并继续检查；
       2. 若非空闲且不是必借角色，无法组成，回上一步。
       然后将角色放回。

    直到有一条路径凑满15名角色，证明队伍可用，结束。
   */
  let resultTeamGroups = [];
  teamGroups.forEach(teamGroup => {
    devLog("检查组合", teamGroup);
    let box_ = copyObject(box); // 复制出来一个box，不要对原先的box进行操作
    /* 生成借用角色列表 */
    let borrowCharacterList = new Array();
    for (let i = 0; i < teamGroup.length; i++) {
      if (teamGroup[i].borrow) borrowCharacterList.push(teamGroup[i].borrow);
      else borrowCharacterList.push(null);
    }
    /* 结果路径 */
    let resultCharactersList = new Array();
    /* 二叉树搜索函数 */
    const btPutCharacterIn = (index) => {
      const currentTeamIndex = Math.floor(index / 5);
      const currentCharacterIndex = index % 5;
      const currentCharacterID = teamGroup[currentTeamIndex].characters[currentCharacterIndex];
      devLog(`路径位置：${index}，角色ID：${currentCharacterID}`);
      const boxPop = (id) => {
        for (const i in box_) {
          if (box_[i].id === id) {
            return (box_.splice(i, 1))[0];
          }
        }
        throw new Error(`没有在box中找到角色${id}！`);
      };
      const isFull = () => {
        if (resultCharactersList.length === teamGroup.length * 5) {
          // 如果路径满，输出，并返回真
          devLog("找到一组解", ...resultCharactersList);
          output();
          return true;
        } else if (btPutCharacterIn(index + 1)) return true;
        return false;
      }
      const output = () => {
        let teamGroup_ = copyObject(teamGroup);
        for (const cIndex in resultCharactersList) {
          if (resultCharactersList[cIndex].isBorrow) {
            devLog(`${teamGroup_[Math.floor(cIndex / 5)].name}借${resultCharactersList[cIndex].id}`);
            teamGroup_[Math.floor(cIndex / 5)].borrow = resultCharactersList[cIndex].id;
          }
        }
        devLog('输出结果', teamGroup_);
        resultTeamGroups.push(teamGroup_);
      };
      devLog(teamGroup[currentTeamIndex].filter[currentCharacterID]);

      // 检查左子树
      if (isInBox(box_, currentCharacterID, teamGroup[currentTeamIndex].filter[currentCharacterID])) {
        devLog(`在box中找到了${currentCharacterID}，将其放入路径中继续查找。`);
        let c = boxPop(currentCharacterID);
        resultCharactersList.push({id: currentCharacterID, isBorrow: false});
        if (isFull()) return true;
        resultCharactersList.pop();
        box_.push(c);
      }

      // 检查右子树
      if (!borrowCharacterList[currentTeamIndex]) {
        devLog(`借用${currentCharacterID}放入路径中继续查找。`);
        borrowCharacterList[currentTeamIndex] = currentCharacterID;
        resultCharactersList.push({id: currentCharacterID, isBorrow: true});
        if (isFull()) return true;
        resultCharactersList.pop();
        borrowCharacterList[currentTeamIndex] = null;
      } else if (borrowCharacterList[currentTeamIndex] === currentCharacterID) {
        devLog(`${currentCharacterID}在box中不存在，借用放入路径中继续查找`);
        resultCharactersList.push({id: currentCharacterID, isBorrow: true});
        if (isFull()) return true;
        resultCharactersList.pop();
      }
      devLog(`从第${index}步回退`);
      return false;
    }
    if (btPutCharacterIn(0)) {
    } else devLog('没有找到解……');
  });
  devLog("计算结果", resultTeamGroups);
  return resultTeamGroups;
}

function devLog (...messages) {
  if (dev) console.log(...messages);
}

/*
1. 生成一个队伍组，包含n个队伍；
2. 执行搜索函数：
  a. 判断树是否存在左子节点（从Box中拿出），若有：
    I.   将角色从Box中移到路径中；
    II.  判断是否已完成路径，若是，输出结果并退出；
    III. 进入左子节点继续搜索；
    IV.  将角色从路径中移到Box中；
  b. 判断树是否存在右子节点（可以使用借人位或本身就占用了借人位），若有：
    I.   将角色放入路径中，若原先没有占用借人位，占用所在队伍借人位；
    II.  判断是否已完成路径，若是，输出结果并退出；
    III. 进入右子节点继续搜索；
    IV.  将角色移除路径，若原先没有占用借人位，解除借人位占用；
  c. 回上一步。
 */
